// This is unpublished source code. Michah Lerner 2006

package trieMatch.keywordMatcher;

import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import trieMatch.Interfaces.MapFactory;

/**
 * Store all matchtext as a sorted trie of strings. The "Sequencer" structures the primary facet of a complex input
 * (i.e., the "text" part of a "KMDefinition"). The successive elements are stored as sequence of Tiers, chained as
 * "successors". Any tier with a final element(s) stores the full KMDefinition (as "instances").
 * 
 * @see Sequencer
 * @see KMDefinition
 * @author Michah.Lerner
 */

public class Tiers {

	static final List<KMDefinition> emptyValueRecord = new ArrayList<KMDefinition>(1);
	public static MapFactory mapFactoryInstance;

	Map<String, Tiers> successors; // next step
	ArrayList<KMDefinition> instances; // value(s) of the path

	Tiers() {
		successors = mapFactoryInstance.newMap();
	}

	Tiers(final Sequencer elementIndexer) {
		successors = mapFactoryInstance.newMap();
	}

	Tiers(final Tiers tiers) {
		successors = mapFactoryInstance.newMap();
		if (tiers.instances != null) {
			instances = new ArrayList<KMDefinition>(tiers.instances.size());
			for (final KMDefinition km : tiers.instances) {
				instances.add(new KMDefinition(km));
			}
		}
		if (tiers.successors.size() > 0) {
			for (final Map.Entry<String, Tiers> me : tiers.successors.entrySet()) {
				successors.put(me.getKey(), new Tiers(me.getValue()));
			}
		}
	}

	/**
	 * Add a string to the trie structure
	 * 
	 * @param s
	 *            the string to add
	 */
	public void add(final String s) {
		add(new KMDefinition(s));
	}

	/**
	 * Add a keymatch to the trie
	 * 
	 * @param kmDef
	 */

	public void add(final KMDefinition kmDef) {
		add(kmDef, kmDef.element);
	}

	public void add(final KMDefinition kmDef, final StructuredElement element) {
		Tiers current = this;
		Tiers prior = null;
		for (final Atom atom : element) {
			if (!current.successors.containsKey(atom.getValue())) {
				final Tiers next = new Tiers();
				current.successors.put(atom.getValue(), next);
				prior = current;
				current = next;
			} else {
				prior = current;
				current = current.successors.get(atom.getValue());
			}
			prior.successors.put(atom.getValue(), current);
		}
		if (current.instances == null) {
			current.instances = new ArrayList<KMDefinition>();
		}
		current.instances.add(kmDef);
	}

	static List<String> ol = new ArrayList<String>();

	public void printTiers(final PrintStream out) {
		out.println(_printTiers("R.").toString());
		Collections.sort(ol);
		for (final String s : ol) {
			System.out.println(s);
		}
	}

	private StringBuilder _printTiers(final String prefix) {
		final StringBuilder sb = new StringBuilder(80);
		int n = 1;
		if (instances != null) {
			for (final KMDefinition kmde : instances) {
				final String string = String.format("%-20s %s", String.format("%s%d", prefix, n++), kmde.asString());
				System.out.println(string);
				ol.add(string);
			}
		}
		n = 1;
		if (successors != null) {
			for (final Map.Entry<String, Tiers> succ : successors.entrySet()) {
				succ.getValue()._printTiers(String.format("%s%d.", prefix, n++));
			}
		}
		return sb;
	}
}
